using System.Collections.Generic;
using System;
using Newtonsoft.Json;
using FrameWork;
using Newtonsoft.Json.Linq;
using UnityEngine;
using System.Linq;

namespace GameFrameWork
{
    /// <summary>
    /// 存档模块
    /// </summary>
    public class StorageModule : GameBaseModule
    {
        /// <summary>
        /// 所有的存档
        /// </summary>
        private Dictionary<string, StorageBase> _storages;

        /// <summary>
        /// 存档缓存
        /// </summary>
        private Dictionary<string, StorageBase> _storageTemp;

        /// <summary>
        /// 脏存档
        /// </summary>
        private List<StorageBase> _dirtyStorages;

        /// <summary>
        /// 文件管理
        /// </summary>
        private FileModule _fileModule;

        /// <summary>
        /// 存档转换器
        /// </summary>
        private StorageConverter _converter;

        /// <summary>
        /// 所有存档的Json类
        /// 游戏中的改动都会映射到它上面
        /// </summary>
        private JObject _jStroage;

        /// <summary>
        /// 节点映射
        /// </summary>
        private Dictionary<string, JToken> _jTokens;

        public override void Init()
        {
            _fileModule = ModuleGetter.FileModule;
            _storages = new Dictionary<string, StorageBase>();
            _dirtyStorages = new List<StorageBase>();
            _converter = new StorageConverter(this);
            _jTokens = new Dictionary<string, JToken>();
            _storageTemp = new Dictionary<string, StorageBase>();
            RegisterStorages();
            FromJson();
        }

        private void RegisterStorage<T>() where T : StorageBase,new()
        {
            Type t = typeof(T);
            string key = t.FullName;
            if (_storages.ContainsKey(key))
                return;

            _storages[key] = new T();
            _storages[key].Init();
        }

        /// <summary>
        /// 注册所有存档
        /// </summary>
        private void RegisterStorages()
        {
            RegisterStorage<StorageActivity>();
        }

        /// <summary>
        /// 获取存档
        /// </summary>
        public T GetStorage<T>() where T : StorageBase
        {
            Type t = typeof(T);
            string key = t.FullName;

            StorageBase storage;

            if (_storageTemp.TryGetValue(key, out storage))
                return (T)storage;

            storage = GetStorage(key);

            if (storage == null)
                throw new NullReferenceException("空存档异常");

            return (T)storage;
        }

        public StorageBase GetStorage(string fullName)
        {
            if (_storages.TryGetValue(fullName, out var storage))
                return storage;
            else
            {
                storage = RecursionFindStorage(fullName);
                return storage;
            }
        }

        /// <summary>
        /// 递归查找存档
        /// </summary>
        private StorageBase RecursionFindStorage(string key)
        {
            foreach (StorageBase storageItem in _storages.Values)
            {
                var storage = storageItem.GetStorage(key);
                if (storage != null)
                    return storage;
            }

            return null;
        }

        public override void ShutDown()
        {
            ToJson();
            _fileModule = null;
            _storages.Clear();
            _dirtyStorages.Clear();
            _converter = null;
            _jTokens.Clear();
            _storageTemp.Clear();
        }

        public override void Update(float deltaTime, float realDeltaTime)
        {
            _dirtyStorages.Clear();

            foreach(var storage in _storages.Values)
            {
                storage.GetDirtyStorage(_dirtyStorages);
            }

            if (_dirtyStorages.Count == 0)
                return;

            string userDataStr = GetUserStr();
            if (string.IsNullOrEmpty(userDataStr))
            {
                ToJson();
                return;
            }

            //是否有新存档
            bool isNew = false;

            foreach(var dirtyStorage in _dirtyStorages)
            {
                string key = dirtyStorage.Key;

                //新存档的jsonStr
                string nodeValue = SerializeNode(dirtyStorage);

                JToken jToken = GetJToken(key);

                //游戏中创建了新的档
                if (jToken == null)
                    isNew = true;
                
                if (isNew)
                    break;

                //新节点
                JToken resultToken = JToken.Parse(nodeValue);
                jToken.Replace(resultToken);

                //替换原有的Token
                if (!_jTokens.ContainsKey(key) || (_jTokens[key] != resultToken))
                    _jTokens[key] = resultToken;
            }

            //如果有新存档，直接重新做个新的
            if(isNew)
            {
                Debug.Log("有崭新的存档，重新做一个新的.");
                ToJson();
                return;
            }

            ToJsonFromJObJ();
        }

        /// <summary>
        /// Jobject中查找原有的存档
        /// </summary>
        private JToken GetJToken(string key)
        {
            if (_jTokens.TryGetValue(key, out JToken jToken))
                return jToken;
            else
            {
                return _jStroage.Descendants().
                    Where(t => t.Type == JTokenType.Property && ((JProperty)t).Name == key).
                    Select(p => ((JProperty)p).Value).First();
            }
        }

        /// <summary>
        /// 读取存档,这里依旧要递归去配置存档数据
        /// </summary>
        private void FromJson()
        {
            string userDataStr = GetUserStr();
            if (string.IsNullOrEmpty(userDataStr))
                return;

            //XOR解密
            userDataStr = EncryptorDecryptor.EncryptDecrypt(userDataStr);
            _jStroage = JObject.Parse(userDataStr);
            _storages = JsonConvert.DeserializeObject<Dictionary<string, StorageBase>>(userDataStr, _converter);
        }

        /// <summary>
        /// 获取用户数据
        /// </summary>
        private string GetUserStr()
        {
            string storagePath = ProjectConfig.UserDataPath;
            string userDataStr = _fileModule.ReadFromPath(storagePath);
            if (string.IsNullOrEmpty(userDataStr))
                return string.Empty;

            return userDataStr;
        }

        /// <summary>
        /// 存档
        /// </summary>
        private void ToJson()
        {
            JsonSerializerSettings settings = new JsonSerializerSettings();
            settings.NullValueHandling = NullValueHandling.Ignore;
            string jsonStr = JsonConvert.SerializeObject(_storages, Formatting.Indented, settings);
            _jStroage = JObject.FromObject(_storages);
            _jTokens.Clear();

            //XOR加密
            jsonStr = EncryptorDecryptor.EncryptDecrypt(jsonStr);
            _fileModule.WriteToPath(jsonStr, ProjectConfig.UserDataPath);
        }

        /// <summary>
        /// 从JObject写入本地数据
        /// </summary>
        private void ToJsonFromJObJ()
        {
            //写入本地数据
            string jsonStr = EncryptorDecryptor.EncryptDecrypt(_jStroage.ToString());
            _fileModule.WriteToPath(jsonStr, ProjectConfig.UserDataPath);
        }

        /// <summary>
        /// 转化节点值
        /// </summary>
        private string SerializeNode(StorageBase storageBase)
        {
            JsonSerializerSettings settings = new JsonSerializerSettings();
            settings.NullValueHandling = NullValueHandling.Ignore;
            string jsonStr = JsonConvert.SerializeObject(storageBase, Formatting.Indented, settings);
            return jsonStr;
        }
    }
}